home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc / Sample Code / Sample Editors⁄Viewers / Sound Editor / Source / SoundHandling.cpp < prev    next >
Encoding:
Text File  |  1995-12-11  |  17.0 KB  |  734 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        SoundHandling.cpp
  3.  
  4.     Contains:    CSounder, CPlayer, and CRecorder classes implementation.
  5.  
  6.     Written by:    Andrey Dolgachev
  7.  
  8.     Copyright:    © 1994 - 1995 by Apple Computer, Inc., all rights reserved.
  9. */
  10.  
  11. // -- Compiler/Preprocessor Switches --
  12.  
  13. #ifndef _COMPILERDEFS_
  14. #include "CompDefs.h"
  15. #endif
  16.  
  17. // -- OpenDoc Utilities --
  18.  
  19. #ifndef _EXCEPT_
  20. // Exceptions define several important macros (eg. CHECKENV)
  21. // which are used in the SOM method dispatch glue. If Except.h
  22. // is not included early enough, exceptions may not be thrown
  23. // correctly when returning from a SOM method with the "ev" parameter set.
  24. #include <Except.h>
  25. #endif
  26.  
  27. // -- SoundEditor Includes --
  28.  
  29. #ifndef _SOUNDHANDLING_
  30. #include "SoundHandling.h"
  31. #endif
  32.  
  33. // -- OpenDoc Includes --
  34.  
  35. #ifndef _ODMEMORY_
  36. #include <ODMemory.h>
  37. #endif
  38.  
  39.  
  40. #pragma segment SoundHandling
  41.  
  42. //------------------------------------------------------------------------------
  43. // Constants
  44. //------------------------------------------------------------------------------
  45. const ODSLong kNULLSoundDevice = -1;
  46.  
  47. //==============================================================================
  48. // CSounder
  49. //==============================================================================
  50.  
  51. //------------------------------------------------------------------------------
  52. // CSounder::CSounder
  53. //------------------------------------------------------------------------------
  54.  
  55. CSounder::CSounder()
  56. {
  57.     SOM_Trace("CSounder","Constructor");
  58.     
  59.     fSoundHandle        = kODNULL;
  60.     fMeterLevel            = 0;
  61.  
  62.     fInitialized        = kODFalse;
  63.     fSounding            = kODFalse;
  64.     fPaused                = kODFalse;
  65.     
  66.     fFrame                = kODNULL;
  67.  
  68.     fStartSecs            = 0;
  69.     fCurrentTime        = 0;
  70.     fPausedSecs            = 0;
  71.     fPauseStart            = 0;
  72.     fPauseEnd            = 0;
  73. }
  74.  
  75. //------------------------------------------------------------------------------
  76. // CSounder::~CSounder
  77. //------------------------------------------------------------------------------
  78.  
  79. CSounder::~CSounder()
  80. {
  81.     SOM_Trace("CSounder","Destructor");
  82.  
  83. }
  84.  
  85. //------------------------------------------------------------------------------
  86. // CSounder::Start
  87. //------------------------------------------------------------------------------
  88.  
  89. ODBoolean CSounder::Start(ODFrame* frame)
  90. {
  91.     SOM_Trace("CSounder","Start");
  92.  
  93.     fSounding         = kODTrue;
  94.     fPaused            = kODFalse;
  95.     fFrame             = frame;
  96.     
  97.     // Time management
  98.     GetDateTime(&fStartSecs);
  99.     fCurrentTime     = 0;
  100.     fPausedSecs     = 0;
  101.  
  102.     return kODTrue;
  103. }
  104.  
  105. //------------------------------------------------------------------------------
  106. // CSounder::Stop
  107. //------------------------------------------------------------------------------
  108.  
  109. ODBoolean CSounder::Stop()
  110. {
  111.     SOM_Trace("CSounder","Stop");
  112.  
  113.     if ( fPaused )
  114.         this->Resume();
  115.         
  116.     fMeterLevel     = 0;        
  117.     fSounding         = 0;
  118.     fFrame             = kODNULL;
  119.  
  120.     return kODTrue;
  121. }
  122.  
  123. //------------------------------------------------------------------------------
  124. // CSounder::Pause
  125. //------------------------------------------------------------------------------
  126.  
  127. ODBoolean CSounder::Pause()
  128. {
  129.     SOM_Trace("CSounder","Pause");
  130.  
  131.     fPaused = kODTrue;
  132.     GetDateTime(&fPauseStart);
  133.  
  134.     return kODTrue;
  135. }
  136.  
  137. //------------------------------------------------------------------------------
  138. // CSounder::Resume
  139. //------------------------------------------------------------------------------
  140.  
  141. ODBoolean CSounder::Resume()
  142. {
  143.     SOM_Trace("CSounder","Resume");
  144.  
  145.     fPaused = kODFalse;
  146.     GetDateTime(&fPauseEnd);
  147.     fPausedSecs += fPauseEnd - fPauseStart;
  148.  
  149.     return kODTrue;
  150. }
  151.  
  152. //------------------------------------------------------------------------------
  153. // CSounder::IsCompleted
  154. //------------------------------------------------------------------------------
  155.  
  156. ODBoolean CSounder::IsCompleted()
  157. {
  158.     SOM_Trace("CSounder","IsCompleted");
  159.  
  160.     if ( !fPaused && fSounding )    
  161.     {
  162.         GetDateTime(&fCurrentTime);
  163.         fCurrentTime -= fStartSecs;
  164.         fCurrentTime -= fPausedSecs;
  165.     }
  166.  
  167.     return kODTrue;
  168. }
  169.  
  170. //------------------------------------------------------------------------------
  171. // CSounder::DisposeSound
  172. //------------------------------------------------------------------------------
  173.  
  174. void CSounder::DisposeSound()
  175. {
  176.     if ( fSoundHandle )
  177.         ODDisposeHandle(fSoundHandle);
  178.     fSoundHandle = kODNULL;
  179. }
  180.  
  181. //==============================================================================
  182. // CCPlayer
  183. //==============================================================================
  184.  
  185. //------------------------------------------------------------------------------
  186. // CPlayer::CPlayer
  187. //------------------------------------------------------------------------------
  188.  
  189. CPlayer::CPlayer()
  190. {
  191.     SOM_Trace("CPlayer","Constructor");
  192.     
  193.     this->Stop();
  194.  
  195.     fSoundChannel        = kODNULL;
  196.     fSoundChannelRate     = 0; 
  197. }
  198.  
  199. //------------------------------------------------------------------------------
  200. // CPlayer::~CPlayer
  201. //------------------------------------------------------------------------------
  202.  
  203. CPlayer::~CPlayer()
  204. {
  205.     SOM_Trace("CPlayer","Destructor");
  206. }
  207.  
  208. //------------------------------------------------------------------------------
  209. // CPlayer::Initialize
  210. //------------------------------------------------------------------------------
  211.  
  212. ODBoolean CPlayer::Initialize()
  213. {
  214.     SOM_Trace("CPlayer","Initialize");
  215.  
  216.     if ( fSoundChannel != kODNULL )
  217.         this->DeInitialize();
  218.     
  219.     if ( SndNewChannel(    &fSoundChannel, sampledSynth,
  220.                         initStereo, kODNULL ) == noErr )
  221.     {
  222.         CSounder::Initialize();
  223.     }
  224.     else
  225.     {
  226.         fSoundChannel = kODNULL;
  227.         CSounder::DeInitialize();
  228.     }
  229.     
  230.     return this->IsInitialized();
  231. }
  232.  
  233. //------------------------------------------------------------------------------
  234. // CPlayer::DeInitialize
  235. //------------------------------------------------------------------------------
  236.  
  237. ODBoolean CPlayer::DeInitialize()
  238. {
  239.     SOM_Trace("CPlayer","DeInitialize");
  240.  
  241.     if ( fSoundChannel != kODNULL )
  242.     {
  243.         SndDisposeChannel(fSoundChannel, kODTrue);
  244.         fSoundChannel = kODNULL;        
  245.     }
  246.     
  247.     CSounder::DeInitialize();
  248.     
  249.     return !this->IsInitialized();
  250. }
  251.  
  252. //------------------------------------------------------------------------------
  253. // CPlayer::Start
  254. //------------------------------------------------------------------------------
  255.  
  256. ODBoolean CPlayer::Start(ODFrame* frame)
  257. {
  258.     SOM_Trace("CPlayer","Start");
  259.  
  260.     if ( fSoundChannel == kODNULL )
  261.         return kODFalse;
  262.  
  263.     if ( !this->IsPlaying() )
  264.     {
  265.         ODLockHandle(fSoundHandle);
  266.         OSErr myErr = SndPlay( fSoundChannel, (SndListHandle) fSoundHandle, kODTrue );
  267.     
  268.         if ( myErr != noErr )
  269.             return kODFalse;
  270.         
  271.         fMeterLevel = 4;
  272.  
  273.         CSounder::Start(frame);        
  274.     }
  275.  
  276.     return this->IsPlaying();
  277. }
  278.  
  279. //------------------------------------------------------------------------------
  280. // CPlayer::Stop
  281. //------------------------------------------------------------------------------
  282.  
  283. ODBoolean CPlayer::Stop()
  284. {
  285.     SOM_Trace("CPlayer","Stop");
  286.  
  287.     if ( fSoundChannel == kODNULL )
  288.         return kODFalse;
  289.  
  290.     if ( this->IsPlaying() )
  291.     {
  292.         OSErr         myErr;
  293.         SndCommand    soundCmd;
  294.         
  295.         soundCmd.cmd = flushCmd;
  296.         soundCmd.param1 = 0;
  297.         soundCmd.param2 = 0;
  298.         myErr = SndDoImmediate(fSoundChannel, &soundCmd);
  299.     
  300.         if ( myErr != noErr )
  301.             return kODFalse;
  302.         
  303.         soundCmd.cmd = quietCmd;
  304.         myErr = SndDoImmediate(fSoundChannel, &soundCmd);
  305.  
  306.         if ( myErr != noErr )
  307.             return kODFalse;
  308.         
  309.         ODUnlockHandle(fSoundHandle);
  310.  
  311.         fSoundChannelRate = 0;
  312.         CSounder::Stop();
  313.     }
  314.     
  315.     return !this->IsPlaying();
  316. }
  317.  
  318. //------------------------------------------------------------------------------
  319. // CPlayer::Pause
  320. //------------------------------------------------------------------------------
  321.  
  322. ODBoolean CPlayer::Pause()
  323. {
  324.     SOM_Trace("CPlayer","Pause");
  325.     
  326.     if ( fSoundChannel == kODNULL )
  327.         return kODFalse;
  328.         
  329.     if ( !this->IsPaused() )
  330.     {
  331.         OSErr         myErr;
  332.         SndCommand    soundCmd;
  333.  
  334.         // save the old rate that the current sound was playing at
  335.         soundCmd.cmd = getRateCmd;
  336.         soundCmd.param1 = 0;
  337.         soundCmd.param2 = (long) &fSoundChannelRate;
  338.         myErr = SndDoImmediate(fSoundChannel, &soundCmd);
  339.         
  340.         if ( myErr != noErr )
  341.             return kODFalse;
  342.         
  343.         // set the rate to zero - pause the sound
  344.         soundCmd.cmd = rateCmd;
  345.         soundCmd.param1 = 0;
  346.         soundCmd.param2 = 0;
  347.         myErr = SndDoImmediate(fSoundChannel, &soundCmd);
  348.         
  349.         if ( myErr != noErr )
  350.             return kODFalse;
  351.  
  352.         CSounder::Pause();
  353.     }
  354.     
  355.     return this->IsPaused();
  356. }
  357.  
  358. //------------------------------------------------------------------------------
  359. // CPlayer::Resume
  360. //------------------------------------------------------------------------------
  361.  
  362. ODBoolean CPlayer::Resume()
  363. {
  364.     SOM_Trace("CPlayer","Resume");
  365.  
  366.     if ( fSoundChannel == kODNULL )
  367.         return kODFalse;
  368.         
  369.     if ( this->IsPaused() )
  370.     {
  371.         OSErr         myErr;
  372.         SndCommand    soundCmd;
  373.  
  374.         soundCmd.cmd = rateCmd;
  375.         soundCmd.param1 = 0;
  376.         soundCmd.param2 = fSoundChannelRate;
  377.         myErr = SndDoImmediate(fSoundChannel, &soundCmd);
  378.         
  379.         if ( myErr != noErr )
  380.             return kODFalse;
  381.         
  382.         fSoundChannelRate = 0; 
  383.         CSounder::Resume();
  384.     }
  385.     
  386.     return !this->IsPaused();
  387. }
  388.  
  389. //------------------------------------------------------------------------------
  390. // CPlayer::IsCompleted
  391. //------------------------------------------------------------------------------
  392.  
  393. ODBoolean CPlayer::IsCompleted()
  394. {
  395.     SOM_Trace("CPlayer","IsCompleted");
  396.  
  397.     SCStatus    state;
  398.     OSErr        myErr;
  399.     ODBoolean    playing = kODTrue;
  400.  
  401.     if ( fSoundChannel == kODNULL )
  402.         return kODTrue;
  403.         
  404.     myErr = SndChannelStatus(fSoundChannel, (short) sizeof(SCStatus), 
  405.                              (SCStatusPtr) &state);
  406.     
  407.     if ( myErr != noErr )
  408.         return kODTrue;
  409.     
  410.     playing = state.scChannelBusy;
  411.  
  412.     if ( !this->IsPaused() )
  413.     { 
  414.         CSounder::IsCompleted();
  415.     }
  416.     
  417.     return !playing;
  418. }
  419.  
  420. //==============================================================================
  421. // CRecorder
  422. //==============================================================================
  423.  
  424. //------------------------------------------------------------------------------
  425. // CRecorder::CRecorder
  426. //------------------------------------------------------------------------------
  427.  
  428. CRecorder::CRecorder()
  429. {
  430.     SOM_Trace("CRecorder","Constructor");
  431.     
  432.     fSoundDevice        = kNULLSoundDevice;
  433.  
  434.     fRecordingQuality    = siGoodQuality;
  435. }
  436.  
  437. //------------------------------------------------------------------------------
  438. // CRecorder::~CRecorder
  439. //------------------------------------------------------------------------------
  440.  
  441. CRecorder::~CRecorder()
  442. {
  443.     SOM_Trace("CRecorder","Destructor");
  444.  
  445.     this->Stop();        
  446.     this->DeInitialize();        
  447. }
  448.  
  449. //------------------------------------------------------------------------------
  450. // CRecorder::Initialize
  451. //------------------------------------------------------------------------------
  452.  
  453. ODBoolean CRecorder::Initialize()
  454. {
  455.     SOM_Trace("CRecorder","Initialize");
  456.  
  457.     if ( fSoundDevice != kNULLSoundDevice )
  458.         this->DeInitialize();
  459.     
  460.     Str255        dName;
  461.     ODSShort    async;
  462.  
  463.     dName[0] = 0;
  464.     if ( SPBOpenDevice(dName, siWritePermission, &fSoundDevice) != noErr )
  465.     {
  466.         fSoundDevice = kNULLSoundDevice;
  467.         CSounder::DeInitialize();
  468.         return kODFalse;
  469.     }
  470.  
  471.     SPBGetDeviceInfo(fSoundDevice, siAsync, &async);        
  472.     if ( async )
  473.         CSounder::Initialize();
  474.     else
  475.         this->DeInitialize();
  476.         
  477.     return this->IsInitialized();
  478. }
  479.  
  480. //------------------------------------------------------------------------------
  481. // CRecorder::DeInitialize
  482. //------------------------------------------------------------------------------
  483.  
  484. ODBoolean CRecorder::DeInitialize()
  485. {
  486.     SOM_Trace("CRecorder","DeInitialize");
  487.  
  488.     if ( fSoundDevice != kNULLSoundDevice )
  489.         SPBCloseDevice(fSoundDevice);
  490.  
  491.     fSoundDevice = kNULLSoundDevice;
  492.     CSounder::DeInitialize();
  493.     
  494.     fSoundHandle = kODNULL;
  495.     
  496.     return !this->IsInitialized();
  497. }
  498.  
  499. //------------------------------------------------------------------------------
  500. // CRecorder::Start
  501. //------------------------------------------------------------------------------
  502.  
  503. ODBoolean CRecorder::Start(ODFrame* frame)
  504. {
  505.     SOM_Trace("CRecorder","Start");
  506.  
  507.     if ( fSoundDevice == kNULLSoundDevice )
  508.         return kODFalse;
  509.  
  510.     if ( !this->IsRecording() )
  511.     {
  512.         OSErr         myErr;
  513.         Size        availMem = ODGetHandleSize( fSoundHandle );
  514.         ODSShort    headLen;
  515.         ODSShort     numChannels;
  516.         ODSShort     sampleSize;
  517.         Fixed        sampleRate;
  518.         OSType        cType;
  519.         
  520.         // Get device information and setup the sound header                
  521.         myErr = SPBGetDeviceInfo(fSoundDevice, siNumberChannels, &numChannels);
  522.         myErr = SPBGetDeviceInfo(fSoundDevice, siSampleRate, &sampleRate);
  523.         myErr = SPBGetDeviceInfo(fSoundDevice, siSampleSize, &sampleSize);
  524.         myErr = SPBGetDeviceInfo(fSoundDevice, siCompressionType, &cType);
  525.         myErr = SetupSndHeader( (SndListHandle) fSoundHandle, numChannels, 
  526.                                 sampleRate, sampleSize,
  527.                                 cType, kMiddleC, 0, &headLen );
  528.         availMem -= headLen;            
  529.         
  530.         // Set up the sound input parameter block
  531.         sPar.inRefNum             = fSoundDevice;
  532.         sPar.count                 = availMem;
  533.         sPar.milliseconds         = 0;
  534.         sPar.bufferLength         = availMem;
  535.         sPar.bufferPtr             = Ptr (*fSoundHandle + headLen);
  536.         sPar.completionRoutine     = kODNULL;
  537.         sPar.interruptRoutine     = kODNULL;
  538.         sPar.userLong             = 0;
  539.         sPar.error                 = noErr;
  540.         sPar.unused1             = 0;
  541.         
  542.         // Start recording (asynchronously)
  543.         ODLockHandle(fSoundHandle);
  544.  
  545.         SPBSetDeviceInfo(fSoundDevice, siRecordingQuality, &fRecordingQuality);        
  546.         myErr = SPBRecord(&sPar, kODTrue);
  547.  
  548.         if ( myErr != noErr )
  549.         {
  550.             this->DeInitialize();
  551.             return kODFalse;
  552.         }
  553.         
  554.         fMeterLevel = 0;
  555.         CSounder::Start(frame);        
  556.     }
  557.  
  558.     return this->IsRecording();
  559. }
  560.  
  561. //------------------------------------------------------------------------------
  562. // CRecorder::Stop
  563. //------------------------------------------------------------------------------
  564.  
  565. ODBoolean CRecorder::Stop()
  566. {
  567.     SOM_Trace("CRecorder","Stop");
  568.  
  569.     if ( fSoundDevice == kNULLSoundDevice )
  570.         return kODFalse;
  571.  
  572.     if ( this->IsRecording() )
  573.     {
  574.         OSErr         myErr;
  575.  
  576.         myErr = SPBStopRecording(fSoundDevice);
  577.     
  578.         if ( myErr != noErr )
  579.             return kODFalse;
  580.             
  581.         ODSShort    headLen;
  582.         ODSShort     numChannels;
  583.         ODSShort     sampleSize;
  584.         Fixed        sampleRate;
  585.         OSType        cType;
  586.                 
  587.         // Get device information and setup the sound header
  588.         myErr = SPBGetDeviceInfo(fSoundDevice, siNumberChannels, &numChannels);
  589.         myErr = SPBGetDeviceInfo(fSoundDevice, siSampleRate, &sampleRate);
  590.         myErr = SPBGetDeviceInfo(fSoundDevice, siSampleSize, &sampleSize);
  591.         myErr = SPBGetDeviceInfo(fSoundDevice, siCompressionType, &cType);
  592.         myErr = SetupSndHeader( (SndListHandle) fSoundHandle, numChannels, 
  593.                                 sampleRate, sampleSize, cType, kMiddleC, 
  594.                                 sPar.count, &headLen);
  595.  
  596.         ODUnlockHandle(fSoundHandle);
  597.         ODSetHandleSize(fSoundHandle, (size_t) sPar.count);
  598.         
  599.         CSounder::Stop();
  600.     }
  601.  
  602.     return !this->IsRecording();
  603. }
  604.  
  605. //------------------------------------------------------------------------------
  606. // CRecorder::Pause
  607. //------------------------------------------------------------------------------
  608.  
  609. ODBoolean CRecorder::Pause()
  610. {
  611.     SOM_Trace("CRecorder","Pause");
  612.     
  613.     if ( fSoundDevice == kNULLSoundDevice )
  614.         return kODFalse;
  615.         
  616.     if ( !this->IsPaused() )
  617.     {
  618.         OSErr myErr = SPBPauseRecording(fSoundDevice);
  619.         
  620.         if ( myErr != noErr )
  621.             return kODFalse;
  622.  
  623.         CSounder::Pause();
  624.     }
  625.     
  626.     return this->IsPaused();
  627. }
  628.  
  629. //------------------------------------------------------------------------------
  630. // CRecorder::Resume
  631. //------------------------------------------------------------------------------
  632.  
  633. ODBoolean CRecorder::Resume()
  634. {
  635.     SOM_Trace("CRecorder","Resume");
  636.  
  637.     if ( fSoundDevice == kNULLSoundDevice )
  638.         return kODFalse;
  639.         
  640.     if ( this->IsPaused() )
  641.     {
  642.         OSErr myErr = SPBResumeRecording(fSoundDevice);
  643.  
  644.         if ( myErr != noErr )
  645.             return kODFalse;
  646.         
  647.         CSounder::Resume();
  648.     }
  649.     
  650.     return !this->IsPaused();
  651. }
  652.  
  653. //------------------------------------------------------------------------------
  654. // CRecorder::GetMaxTime
  655. //------------------------------------------------------------------------------
  656.  
  657. ODSLong CRecorder::GetMaxTime(ODSLong MaxSize, OSType rQuality)
  658. {
  659.     ODSLong     maxSeconds;
  660.     ODBoolean    wasInitialized = kODFalse;
  661.     
  662.     if ( fSoundDevice == kNULLSoundDevice )
  663.         this->Initialize();
  664.     else
  665.         wasInitialized = kODTrue;
  666.                
  667.     SPBSetDeviceInfo(fSoundDevice, siRecordingQuality, &rQuality);        
  668.        maxSeconds = MaxSize;
  669.        if ( SPBBytesToMilliseconds(fSoundDevice, &maxSeconds) == noErr )
  670.            maxSeconds /= 1000;    
  671.        else
  672.            maxSeconds = 0;
  673.        
  674.     if ( !wasInitialized )    
  675.            this->DeInitialize();
  676.        else
  677.         SPBSetDeviceInfo(fSoundDevice, siRecordingQuality, &fRecordingQuality);        
  678.            
  679.        return maxSeconds;    
  680. }
  681.  
  682. //------------------------------------------------------------------------------
  683. // CRecorder::SetQuality
  684. //------------------------------------------------------------------------------
  685.  
  686. void CRecorder::SetQuality(OSType rQuality)
  687. {
  688.     SOM_Trace("CRecorder","SetQuality");
  689.  
  690.     fRecordingQuality = rQuality;
  691.  
  692.     if ( this->IsInitialized() )
  693.         SPBSetDeviceInfo(fSoundDevice, siRecordingQuality, &fRecordingQuality);            
  694. }
  695.  
  696. //------------------------------------------------------------------------------
  697. // CRecorder::IsCompleted
  698. //------------------------------------------------------------------------------
  699.  
  700. ODBoolean CRecorder::IsCompleted()
  701. {
  702.     SOM_Trace("CRecorder","IsCompleted");
  703.  
  704.     OSErr        myErr;
  705.     ODSShort    recStatus, mLevel;
  706.     ODULong        sToRecord, sRecorded, mToRecord, mRecorded;
  707.     ODBoolean    recording = kODTrue;
  708.  
  709.     if ( fSoundDevice == kNULLSoundDevice )
  710.         return kODTrue;
  711.         
  712.     myErr = SPBGetRecordingStatus(fSoundDevice, &recStatus, &mLevel, 
  713.                                   &sToRecord, &sRecorded, 
  714.                                   &mToRecord, &mRecorded );
  715.     if ( myErr != noErr )
  716.         return kODTrue;
  717.     
  718.     recording = (recStatus > 0);
  719.  
  720.     fMeterLevel = mLevel / 30;
  721.     if ( fMeterLevel < 0 )
  722.         fMeterLevel = 0;
  723.     if ( fMeterLevel > 5 )
  724.         fMeterLevel = 5;
  725.  
  726.     if ( !this->IsPaused() )
  727.     { 
  728.         CSounder::IsCompleted();
  729.     }
  730.     
  731.     return !recording;
  732. }
  733.  
  734.